﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TestUnspscRepository.cs" company="wwwlicious">
//   All rights reserved 2009.
// </copyright>
// <summary>
//   Defines the TestUnspscRepository type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Unspsc.Data
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Audit;

    internal class TestUnspscRepository : IUnspscRepository
    {
        private readonly IList<IUnspscElement> classList;
        private readonly IList<IUnspscElement> commodityList;
        private readonly IList<IUnspscElement> familyList;
        private readonly IList<IUnspscElement> segmentList;
        private readonly IList<double> versionList;

        internal TestUnspscRepository()
        {
            // load up the segments
            segmentList = new List<IUnspscElement>();

            // load up the versions
            versionList = this.GetVersions().ToList();

            foreach (double version in versionList)
            {
                for (int i = 0; i <= 4; i++)
                {
                    IUnspscElement p = CreateSegment(i, version);
                    segmentList.Add(p);
                }

                // load up the families
                familyList = new List<IUnspscElement>();
                foreach (var segment in segmentList)
                {
                    this.CreateFamilies(segment);
                }

                // load up the classes
                classList = new List<IUnspscElement>();

                foreach (var family in familyList)
                {
                    this.CreateClasses(family);
                }

                // load up the commodities
                commodityList = new List<IUnspscElement>();
                foreach (var unspscClass in classList)
                {
                    this.CreateCommodities(unspscClass);
                }
            }
        }

        #region IUnspscRepository Members

        /// <summary>
        /// Gets the available versions.
        /// </summary>
        /// <returns>IQueryable of version numbers</returns>
        public IQueryable<double> GetVersions()
        {
            return new List<double> {1, 2, 3}.AsQueryable();
        }

        /// <summary>
        /// Gets the segments.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of IUnspscElement</returns>
        public IQueryable<IUnspscElement> GetSegments(double version)
        {
            return segmentList.AsQueryable().WithVersion(version);
        }

        /// <summary>
        /// Gets the families.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of families</returns>
        public IQueryable<IUnspscElement> GetFamilies(double version)
        {
            return familyList.AsQueryable().WithVersion(version);
        }

        /// <summary>
        /// Gets the families.
        /// </summary>
        /// <param name="unspscCode">The unspsc code.</param>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of IUnspscElement</returns>
        public IQueryable<IUnspscElement> GetFamilies(UnspscCode unspscCode, double version)
        {
            return familyList.AsQueryable().WithSegmentCode(unspscCode).WithVersion(version);
        }

        /// <summary>
        /// Gets the classes.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of classes</returns>
        public IQueryable<IUnspscElement> GetClasses(double version)
        {
            return classList.AsQueryable().WithVersion(version);
        }

        /// <summary>
        /// Gets the classes.
        /// </summary>
        /// <param name="unspscCode">The unspsc code.</param>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of IUnspscElement</returns>
        public IQueryable<IUnspscElement> GetClasses(UnspscCode unspscCode, double version)
        {
            return classList.AsQueryable().WithFamilyCode(unspscCode).WithVersion(version);
        }

        /// <summary>
        /// Gets the commodities.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of commodities</returns>
        public IQueryable<IUnspscElement> GetCommodities(double version)
        {
            return commodityList.AsQueryable().WithVersion(version);
        }

        /// <summary>
        /// Gets the commodities.
        /// </summary>
        /// <param name="unspscCode">The unspsc code.</param>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of IUnspscElement</returns>
        public IQueryable<IUnspscElement> GetCommodities(UnspscCode unspscCode, double version)
        {
            return commodityList.AsQueryable().WithClassCode(unspscCode).WithVersion(version);
        }

        /// <summary>
        /// Gets a IUnspscElement.
        /// </summary>
        /// <param name="unspscCode">The unspsc code.</param>
        /// <param name="version">The version.</param>
        /// <returns>IUnspscElement object</returns>
        public IUnspscElement GetUnspscElement(UnspscCode unspscCode, double version)
        {
            if (unspscCode.IsSegment)
                return segmentList.AsQueryable().WithUnspscCode(unspscCode, version);

            if (unspscCode.IsFamily)
                return familyList.AsQueryable().WithUnspscCode(unspscCode, version);

            if (unspscCode.IsClass)
                return classList.AsQueryable().WithUnspscCode(unspscCode, version);

            return commodityList.AsQueryable().WithUnspscCode(unspscCode, version);
        }

        /// <summary>
        /// Searches commodity titles and descriptions
        /// </summary>
        /// <param name="keywords">The keywords.</param>
        /// <param name="version">The version.</param>
        /// <returns>IQueryable of IUnspscElement</returns>
        /// <exception cref="NotImplementedException">Search is not implemented in the test repository</exception>
        public IQueryable<IUnspscElement> SearchText(string[] keywords, double version)
        {
            throw new NotImplementedException("Search is not implemented in the test repository....yet");
        }

        /// <summary>
        /// Gets the audit log.
        /// </summary>
        /// <param name="code">The unspsc code.</param>
        /// <returns>IQueryable of IAuditItem</returns>
        /// <exception cref="NotImplementedException">Audit is not implemented in the test repository</exception>
        public IQueryable<IAuditItem> GetAuditLog(UnspscCode code)
        {
            throw new NotImplementedException("Audit is not implemented in the test repository.....yet");
        }

        #endregion

        #region Create Test IUnspscElements

        private static IUnspscElement CreateSegment(int key, double version)
        {
            UnspscCode code = UnspscCode.MinValue + (key * 1000000);
            return new UnspscElement
            {
                Key = key,
                Code = code,
                Title = "Segment Title" + code,
                Definition = "Segment Definition" + code,
                Version = version
            };
        }

        private static IUnspscElement CreateFamily(int key, IUnspscElement segment)
        {
            UnspscCode code = (double)segment.Code + (key * 100000);
            return new UnspscElement
            {
                Key = key,
                Code = code,
                Title = "Family Title" + code,
                Definition = "Family Definition" + code,
                Version = segment.Version
            };
        }

        private static IUnspscElement CreateClass(int key, IUnspscElement family)
        {
            UnspscCode code = (double)family.Code + (key * 1000);
            return new UnspscElement
            {
                Key = key,
                Code = code,
                Title = "Class Title" + code,
                Definition = "Class Definition" + code,
                Version = family.Version
            };
        }

        private static IUnspscElement CreateCommodity(int key, IUnspscElement unspscClass)
        {
            UnspscCode code = (double)unspscClass.Code + (key * 10);
            return new UnspscElement
            {
                Key = key,
                Code = code,
                Title = "Commodity Title" + code,
                Definition = "Commodity Definition" + code,
                Version = unspscClass.Version
            };
        } 

        #endregion

        /// <summary>
        /// Creates the families.
        /// </summary>
        /// <param name="segment">The segment.</param>
        private void CreateFamilies(IUnspscElement segment)
        {
            for (int i = 1; i <= 5; i++)
            {
                IUnspscElement p = CreateFamily(i, segment);
                this.familyList.Add(p);
            }
        }

        /// <summary>
        /// Creates the commodities.
        /// </summary>
        /// <param name="unspscClass">The unspsc class.</param>
        private void CreateCommodities(IUnspscElement unspscClass)
        {
            for (int i = 1; i <= 5; i++)
            {
                IUnspscElement p = CreateCommodity(i, unspscClass);
                this.commodityList.Add(p);
            }
        }

        /// <summary>
        /// Creates the classes.
        /// </summary>
        /// <param name="family">The family.</param>
        private void CreateClasses(IUnspscElement family)
        {
            for (int i = 1; i <= 5; i++)
            {
                IUnspscElement p = CreateClass(i, family);
                this.classList.Add(p);
            }
        }
    }
}